/**
 * @license
 * Copyright Alibaba.com All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
 */

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  OnChanges,
  OnDestroy,
  OnInit,
  Output,
  SimpleChanges,
  ViewChild,
  ViewEncapsulation
} from '@angular/core';
import { InputBoolean, isNotNil } from '@shared/apes/core';
import { ApesDropdownMenuComponent } from '@shared/apes/dropdown';
import { ApesI18nInterface, ApesI18nService } from '@shared/apes/i18n';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';


/* tslint:disable-next-line:no-any */
export type ApesThFilterType = Array<{ text: string; value: any; byDefault?: boolean }>;

export interface ApesThItemInterface {
  text: string;
  /* tslint:disable-next-line:no-any */
  value: any;
  checked: boolean;
}

@Component({
  // tslint:disable-next-line:component-selector
  selector: 'th:not(.apes-disable-th):not([mat-sort-header]):not([mat-header-cell])',
  preserveWhitespaces: false,
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  templateUrl: './apes-th.component.html',
  host: {
    '[class.apes-table-column-has-actions]': 'apesShowFilter || apesShowSort || apesCustomFilter',
    '[class.apes-table-column-has-filters]': 'apesShowFilter || apesCustomFilter',
    '[class.apes-table-column-has-sorters]': 'apesShowSort',
    '[class.apes-table-selection-column-custom]': 'apesShowRowSelection',
    '[class.apes-table-selection-column]': 'apesShowCheckbox',
    '[class.apes-table-expand-icon-th]': 'apesExpand',
    '[class.apes-table-th-left-sticky]': 'apesLeft',
    '[class.apes-table-th-right-sticky]': 'apesRight',
    '[class.apes-table-column-sort]': `apesSort === 'descend' || apesSort === 'ascend'`,
    '[style.left]': 'apesLeft',
    '[style.right]': 'apesRight',
    '[style.text-align]': 'apesAlign'
  }
})
export class ApesThComponent implements OnChanges, OnInit, OnDestroy {
  hasFilterValue = false;
  filterVisible = false;
  multipleFilterList: ApesThItemInterface[] = [];
  singleFilterList: ApesThItemInterface[] = [];
  /* tslint:disable-next-line:no-any */
  locale: ApesI18nInterface['Table'] = {} as ApesI18nInterface['Table'];
  apesWidthChange$ = new Subject();
  private destroy$ = new Subject();
  private hasDefaultFilter = false;
  @ViewChild(ApesDropdownMenuComponent, { static: false }) apesDropdownMenuComponent: ApesDropdownMenuComponent;
  /* tslint:disable-next-line:no-any */
  @Input() apesSelections: Array<{ text: string; onSelect(...args: any[]): any }> = [];
  @Input() apesChecked = false;
  @Input() apesDisabled = false;
  @Input() apesIndeterminate = false;
  @Input() apesSortKey: string;
  @Input() apesFilterMultiple = true;
  @Input() apesWidth: string;
  @Input() apesLeft: string;
  @Input() apesRight: string;
  @Input() apesAlign: 'left' | 'right' | 'center';
  @Input() apesSort: 'ascend' | 'descend' | null = null;
  @Input() apesFilters: ApesThFilterType = [];
  @Input() @InputBoolean() apesExpand = false;
  @Input() @InputBoolean() apesShowCheckbox = false;
  @Input() @InputBoolean() apesCustomFilter = false;
  @Input() @InputBoolean() apesShowSort = false;
  @Input() @InputBoolean() apesShowFilter = false;
  @Input() @InputBoolean() apesShowRowSelection = false;
  @Output() readonly apesCheckedChange = new EventEmitter<boolean>();
  @Output() readonly apesSortChange = new EventEmitter<string | null>();
  @Output() readonly apesSortChangeWithKey = new EventEmitter<{ key: string; value: string | null }>();
  /* tslint:disable-next-line:no-any */
  @Output() readonly apesFilterChange = new EventEmitter<any[] | any>();

  updateSortValue(): void {
    if (this.apesShowSort) {
      if (this.apesSort === 'ascend') {
        this.setSortValue('descend');
      } else if (this.apesSort === 'descend') {
        this.setSortValue(null);
      } else {
        this.setSortValue('ascend');
      }
    }
  }

  setSortValue(value: 'ascend' | 'descend' | null): void {
    this.apesSort = value;
    this.apesSortChangeWithKey.emit({ key: this.apesSortKey, value: this.apesSort });
    this.apesSortChange.emit(this.apesSort);
  }

  get filterList(): ApesThItemInterface[] {
    return this.multipleFilterList.filter(item => item.checked).map(item => item.value);
  }

  /* tslint:disable-next-line:no-any */
  get filterValue(): any {
    const checkedFilter = this.singleFilterList.find(item => item.checked);
    return checkedFilter ? checkedFilter.value : null;
  }

  updateFilterStatus(): void {
    if (this.apesFilterMultiple) {
      this.hasFilterValue = this.filterList.length > 0;
    } else {
      this.hasFilterValue = isNotNil(this.filterValue);
    }
  }

  search(): void {
    this.updateFilterStatus();
    if (this.apesFilterMultiple) {
      this.apesFilterChange.emit(this.filterList);
    } else {
      this.apesFilterChange.emit(this.filterValue);
    }
  }

  reset(): void {
    this.initMultipleFilterList(true);
    this.initSingleFilterList(true);
    this.hasFilterValue = false;
  }

  checkMultiple(filter: ApesThItemInterface): void {
    filter.checked = !filter.checked;
  }

  checkSingle(filter: ApesThItemInterface): void {
    this.singleFilterList.forEach(item => (item.checked = item === filter));
  }

  hideDropDown(): void {
    this.apesDropdownMenuComponent.setVisibleStateWhen(false);
    this.filterVisible = false;
  }

  dropDownVisibleChange(value: boolean): void {
    this.filterVisible = value;
    if (!value) {
      this.search();
    }
  }

  initMultipleFilterList(force?: boolean): void {
    this.multipleFilterList = this.apesFilters.map(item => {
      const checked = force ? false : !!item.byDefault;
      if (checked) {
        this.hasDefaultFilter = true;
      }
      return { text: item.text, value: item.value, checked };
    });
    this.checkDefaultFilters();
  }

  initSingleFilterList(force?: boolean): void {
    this.singleFilterList = this.apesFilters.map(item => {
      const checked = force ? false : !!item.byDefault;
      if (checked) {
        this.hasDefaultFilter = true;
      }
      return { text: item.text, value: item.value, checked };
    });
    this.checkDefaultFilters();
  }

  checkDefaultFilters(): void {
    if (!this.apesFilters || this.apesFilters.length === 0 || !this.hasDefaultFilter) {
      return;
    }
    this.updateFilterStatus();
  }

  marForCheck(): void {
    this.cdr.markForCheck();
  }

  constructor(private cdr: ChangeDetectorRef, private i18n: ApesI18nService) {}

  ngOnInit(): void {
    this.i18n.localeChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
      this.locale = this.i18n.getLocaleData('Table');
      this.cdr.markForCheck();
    });
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.apesFilters) {
      this.initMultipleFilterList();
      this.initSingleFilterList();
      this.updateFilterStatus();
    }
    if (changes.apesWidth) {
      this.apesWidthChange$.next(this.apesWidth);
    }
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }
}
